/* mount.h - file system mount-point interface */

/*
 * Copyright 2005 Wind River Systems, Inc.
 *
 * The right to copy, distribute, modify or otherwise make use
 * of this software may be licensed only pursuant to the terms
 * of an applicable Wind River license agreement.
 */

/*
modification history
--------------------
01l,14aug05,jlk  add suspend flag to mountEject
01k,26jul05,act  split commit op into start+end ops
01j,20jul05,act  add mountEject and some internal flags
01i,06may05,jlk  changed some fields in statvs to be 64 bit
01h,21apr05,jlk  filled in statvs structure
01g,10mar05,act  add pointer to mount point to mountCreate
01f,10mar05,act  split buffer creation and deletion out of mountCreate
01e,10mar05,act  add mnt_dev
01d,03mar05,act  add MNT_RDONLY
01c,03mar05,act  remove mount list and some unused mnt_* fields
01b,02mar05,act  add bio fields, and DEV_HDR for coreIO
01a,23feb05,act  add mnt_rootvnode, for lookup code
*/

#ifndef __INCmounth
#define __INCmounth

#include <buf.h>
#include <vnode.h>
#include <ioLib.h>

#ifdef __cplusplus
extern "C" {
#endif

struct vfsops;

/* xxx move this to vnode.h */
LIST_HEAD(vnodelst, vnode);
LIST_HEAD(vhashhdr, vnode);

struct statvfs {
    UINT32  f_bsize;    /* File system block size.                                     */
    UINT32  f_frsize;   /* Fundamental file system block size.                         */
    UINT64  f_blocks;   /* Total number of blocks on file system in units of f_frsize. */
    UINT64  f_bfree;    /* Total number of free blocks.                                */
    UINT64  f_bavail;   /* Number of free blocks available to                          */
                        /* non-privileged process.                                     */
    UINT64  f_files;    /* Total number of file serial numbers.                        */
    UINT64  f_ffree;    /* Total number of free file serial numbers.                   */
    UINT64  f_favail;   /* Number of file serial numbers available to                  */
                        /* non-privileged process.                                     */
    UINT32  f_fsid;     /* File system ID.                                             */
    UINT32  f_flag;     /* Bit mask of f_flag values.                                  */
    UINT32  f_namemax;  /* Maximum filename length.                                    */
};

/*
 * Open-file table, per mount point.  In BSD this is in <sys/file.h>
 * and logically core I/O should do this, but here we have to do it
 * per mount point.
 *
 * At the moment, f_count is not needed... remove it?  (dup() is handled
 * inside core I/O, so that dup()ed fd's point to the same vfile data
 * structure.)
 */
struct vfile {
    	u_short		f_count;		/* number of dup()s */
    	u_short		f_flags;		/* _FREAD and/or _FWRITE */
	struct vnode	*f_vnode;		/* vnode for this file */
	voff_t		f_offset;		/* and current seek pos */
	SLIST_ENTRY(vfile) f_next;		/* list of free files */
};

struct mount {
	DEV_HDR		mnt_devhdr;		/* CoreI/O, MUST BE FIRST */
	device_t	mnt_dev;		/* connected XBD */
	struct vfsops	*mnt_op;		/* operations on fs */
	struct vnode	*mnt_syncer;		/* syncer vnode */
	struct vnode	*mnt_rootvnode;		/* result of VFS_ROOT() */
	struct vnodelst	mnt_vnodelist;		/* active vnodes */
#ifdef notyet
	struct lock	mnt_lock;		/* mount structure lock */
#else
	SEM_ID		mnt_lock;
#endif
	int		mnt_flag;		/* flags */
	int		mnt_iflag;		/* internal flags */

	/* per-mount file and vnode tables */
	SEM_ID		mnt_filesem;		/* ??? can use mnt_lock? */
	struct vfile	*mnt_filetable;		/* open file table */
	int		mnt_nfiles;		/* # files, for debug/show */
	SLIST_HEAD(, vfile) mnt_freefiles;	/* list of free files */
	char		*mnt_vnodespace;	/* malloc() space for vnodes */
	int		mnt_nvnodes;		/* # vnodes, for debug/show */

	void		*mnt_data;		/* private data */

	/*
	 * These items are for buffer management.  Note that there are
	 * three semaphores involved: a counting semaphore for "number of
	 * unowned buffers", a mutex for hash chain manipulation, and
	 * one semaphore per buffer.  If you are taking a buffer semaphore
	 * and the hash chain mutex, you must take the buffer semaphore
	 * first (to avoid deadlocking).
	 *
	 * The hash chain mutex is also used to protect the free lists.
	 *
	 * The buffer getting routines (getblk, bread) return locked
	 * buffers (which are no longer on a free list) -- see buf.h.
	 */
	struct buf	*mnt_bufspace;		/* for free()ing */
	int		mnt_nbufs;		/* and show()ing */
	SEM_ID		mnt_unowned_bufs;	/* number of unowned buffers */
	SEM_ID		mnt_bufhash_mutex;	/* hash chain mutex */
	struct bhashhdr	mnt_bufhash[BUF_BHSIZE]; /* hash chains */
	struct bfreehdr	mnt_bufqueues[BUF_NQUEUES]; /* free lists */

	/*
	 * These items are for vnode management, which is done in pretty
	 * much the same fashion as buffer management, except that vnodes
	 * do not have "priorities" to order the free list.  Also, vnodes
	 * can have more than one active user, and can be "held" (by
	 * buffer cache references) even when no one is using them.
	 */
    	SEM_ID		mnt_unowned_vnodes;	/* number of unowned vnodes */
	SEM_ID		mnt_vhash_mutex;	/* hash chain mutex */
	struct vhashhdr mnt_vhash[VN_VHSIZE];	/* hash chains */
	TAILQ_HEAD(, vnode) mnt_vhold_list;	/* held vnodes */
	TAILQ_HEAD(, vnode) mnt_freevnodes;	/* free vnodes */

	/*
	 * These keep track of bio space allocated in mountCreate(),
	 * for mountDelete() to release.
	 */
	struct bio	*mnt_bios;		/* the bios */
	void		*mnt_biomem;		/* device-space RAM for I/O */
};

struct vfsops {
    	const char *vfs_name;			/* name of this fs type */
	size_t	vfs_mount_data_size;		/* size of private mount data */
	size_t	vfs_vnode_data_size;		/* size of private vnode data */

    	int	(*vfs_start)(struct mount *, int);
	int	(*vfs_unmount)(struct mount *, int);
	int	(*vfs_root)(struct mount *, struct vnode **);
	int	(*vfs_statvfs)(struct mount *, struct statvfs *);
	int	(*vfs_vget)(struct mount *, ino_t, struct vnode **);
	void	(*vfs_init)(void);
	void	(*vfs_reinit)(void);
	void	(*vfs_done)(void);
	int	(*vfs_starttransaction)(struct mount *, BOOL);
	int	(*vfs_endtransaction)(struct mount *, int);
};

#define	VFS_START(mp, flags)	((mp)->mnt_op->vfs_start(mp, flags))
#define	VFS_UNMOUNT(mp, force)	((mp)->mnt_op->vfs_unmount(mp, force))
#define	VFS_ROOT(mp, vpp)	((mp)->mnt_op->vfs_root(mp, vpp))
#define	VFS_STATVFS(mp, sbp)	((mp)->mnt_op->vfs_statvfs(mp, sbp))
#define	VFS_VGET(mp, ino, vpp)	((mp)->mnt_op->vfs_vget(mp, ino, vpp))
#define	VFS_STARTTRANSACTION(mp, willwrite) \
			((mp)->mnt_op->vfs_starttransaction(mp, willwrite))
#define	VFS_ENDTRANSACTION(mp, error) \
			((mp)->mnt_op->vfs_endtransaction(mp, error))

int mountCreate(struct vfsops *, device_t, int, char *, struct mount **);
void mountDelete(struct mount *, int);
void mountEject(struct mount *, BOOL);

int mountBufAlloc(struct mount *, int, size_t);
void mountBufFree(struct mount *);

/*
 * Mount flags.
 */
#define	MNT_RDONLY	0x00000001	/* read only filesystem */

/*
 * Internal flags.
 */
#define	MNTI_IN_COREIO	0x00000001	/* entry is in coreIO tables */
#define	MNTI_EJECTING	0x00000002	/* mount point is being ejected */

#ifdef __cplusplus
}
#endif

#endif /* __INCmounth */
